# -*-coding: utf-8 -*-

from mainwindow import Ui_MainWindow
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import pyqtSlot, Qt
import sys
import traceback
from PfclsAPI import *
import win32con
import win32gui
import re
from math import pi, atan2


class mainwin(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(mainwin, self).__init__(parent)
        self.setupUi(self)
        self.actionconnect.triggered.connect(self.connect)
        self.Asyncconnect = None
        self.connect()

    def closeEvent(self, event):
        self.disconnect()
        event.accept()

    def connect(self):
        try:
            self.Asyncconnect = CCpfcAsyncConnection.Connect(None, None, None, None)
            session = self.Asyncconnect.Session
            model = session.CurrentModel
            self.tbmessage.append('当前连接：' + str(model.FileName))
            self.statusbar.showMessage('连接成功！')
            self.active_creo()

        except Exception as e:
            print('==========connect fail==========')
            print(traceback.format_exc())
            print('==========connect fail==========')

    def disconnect(self):
        try:
            if self.Asyncconnect.IsRunning():
                self.Asyncconnect.Disconnect(None)
                self.tbmessage.append('连接已断开！')
        except Exception as e:
            print('==========disconnect fail!==========')
            print(traceback.format_exc())
            print('==========disconnect fail!==========')

    @pyqtSlot()
    def on_pbconnect_clicked(self):
        self.connect()
    @pyqtSlot()
    def on_pbdisconnect_clicked(self):
        self.disconnect()

    @pyqtSlot()
    def on_pbaddcenter_clicked(self):
        self.active_creo()
        self.select()
    @pyqtSlot()
    def on_pbautoindex_clicked(self):
        self.traverse_dim()
    @pyqtSlot()
    def on_pbcleanindex_clicked(self):
        self.clear_indexsymbol()


    def select(self):
        self.setWindowFlags(Qt.WindowStaysOnBottomHint)
        self.show()
        session = self.Asyncconnect.Session
        try:
            selectoptions = CCpfcSelectionOptions.Create('edge')
            selectoptions.MaxNumSels = 1
            while 1:
                selected = session.Select(selectoptions, None)  # IpfcSelections
                if selected is not None:
                    self.add_centerline(selected)
                else:
                    break

        except Exception as e:
            print('==================select failed!===================')
            print(traceback.format_exc())
            print('==================select failed!===================')

        self.setWindowFlags(Qt.Widget)
        self.show()

    def print_point3D(self, point3D):
        for i in range(3):
            print(point3D.Item(i), end='\t')
        print('\n')

    def transformpoint(self, point3D):
        m = [
            [1, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 0, 1, 0],
            [0, 0, 0, 1]
        ]
        mt = CpfcMatrix3D
        for i in range(4):
            for j in range(4):
                mt.Set(i, j, m[i][j])
        t = CCpfcTransform3D.Create(mt)
        return t.TransformPoint(point3D)

    def transformvector(self, vector3D):
        m = [
            [1, 0, 0, 0],
            [0, 1, 0, 0],
            [0, 0, 1, 0],
            [0, 0, 0, 1]
        ]
        mt = CpfcMatrix3D
        for i in range(4):
            for j in range(4):
                mt.Set(i, j, m[i][j])
        t = CCpfcTransform3D.Create(mt)
        return t.TransformVector(vector3D)

    # 添加中心线
    def add_centerline(self, selected):
        try:
            session = self.Asyncconnect.Session
            selectedge = selected.Item(0)  # IpfcSelection
            modelitem = selectedge.SelItem  # IpfcModelItem
            descriptor = modelitem.GetCurveDescriptor()  # IpfcGeomCurve.GetCurveDescriptor()
            geotype = descriptor.GetCurveType()
            if geotype == EpfcCURVE_ARC:
                model = selectedge.SelModel
                model2D = session.GetModel(model.FullName, EpfcMDL_DRAWING)
                if model2D is None:
                    self.tbmessage.append('fail!')
                else:
                    view2d = selectedge.SelView2D
                    csys = view2d.GetTransform()
                    end1 = csys.TransformPoint(descriptor.Center)
                    end1.Set(2, 0)

                    length = descriptor.Radius + 5
                    end = []
                    for i in range(2):
                        for j in range(2):
                            point = CpfcPoint3D
                            d = end1.Item(i) + length * (1, -1)[j]
                            point.Set(i, d)
                            point.Set((1, 0)[i], end1.Item((1, 0)[i]))
                            end.append(self.transformpoint(point))  # 将CpfcPoint3D对象转为TransFormPoint3D对象
                    linedescriptor1 = CCpfcLineDescriptor.Create(end[0], end[1])
                    linedescriptor2 = CCpfcLineDescriptor.Create(end[2], end[3])
                    lineinstruction = CCpfcDetailEntityInstructions.Create(linedescriptor1, None)
                    lineinstruction.FontName = 'CTRLFONT_MID_L'
                    lineinstruction.Color = CCpfcColorRGB.Create(1, 0, 0)
                    model2D.CreateDetailItem(lineinstruction)
                    lineinstruction.Geometry = linedescriptor2
                    model2D.CreateDetailItem(lineinstruction)
                    session.GetModelWindow(model2D).Repaint()


        except Exception:
            print('==========add center line failed!==========')
            print(traceback.format_exc())
            print('==========add center line failed!==========')

    # 遍历尺寸 添加球标
    def traverse_dim(self):
        # self.clear_indexsymbol()
        try:
            session = self.Asyncconnect.Session
            model = session.CurrentModel
            model2D = session.GetModel(model.FullName, EpfcMDL_DRAWING)
            modelitems = model.ListItems(EpfcITEM_DIMENSION)
            symdef = model2D.RetrieveSymbolDefinition('boolean', 'D:/PTC/config/symbol/', None, True)
            symins = CCpfcDetailSymbolInstInstructions.Create(symdef)
            dimdict = {}
            for i in range(modelitems.Count):
                dim = modelitems.Item(i)
                location = dim.Location
                view = dim.GetView()
                outline = view.Outline
                vieworigin = []
                for k in range(3):
                    o1 = outline.Item(0)[k]
                    o2 = outline.Item(1)[k]
                    vieworigin.append((o1 + o2) / 2)
                angle = atan2(-(location[0] - vieworigin[0]), (location[1] - vieworigin[1]))  # 以竖直向上为起始方向计算夹角
                angle = angle * 180 / pi + 360 if angle < 0 else angle * 180 / pi  # atan2值域为（-pi， pi），角度小于0时加2pi
                dimlist = {'item': dim, 'loc': location, 'angle': angle,
                           'dist': self.eval_distance(location, vieworigin)}
                if not view.Name in dimdict.keys():
                    dimdict[view.Name] = {'viewname': view.Name, 'origin': vieworigin,
                                          'dimlist': [dimlist]}
                else:
                    dimdict[view.Name]['dimlist'].append(dimlist)
                '''
                dimdict = {
                            viewname: 
                                {'viewname': viewname, 
                                'origin': [292.19013094587086, 460.2146567764112, 0.0], 
                                'dimlist': [
                                    {'item': dim, 'loc': location, 'ang': angle, 'dist': dist}, 
                                    {}]
                                },
                            }
                '''
            dimlist = self.sort_dimlist(dimdict)
            i = 1
            for item in dimlist:
                location = item['loc']
                location.Set(0, location[0] - 12)
                location.Set(1, location[1] + 12)
                textvalue = CCpfcDetailVariantText.Create('index', i)
                textvalues = CpfcDetailVariantTexts
                textvalues.Append(textvalue)
                symins.TextValues = textvalues
                selection = CMpfcSelect.CreateModelItemSelection(item['item'], None)
                defattachment = CCpfcSymbolDefAttachment.Create(EpfcATTACH_FREE, location)
                symins.DefAttachment = defattachment
                attachment = CCpfcOffsetAttachment.Create(selection, location)
                leaders = CCpfcDetailLeaders.Create()
                leaders.ItemAttachment = attachment
                symins.InstAttachment = leaders
                symins.IsDisplayed = True
                symins.ScaledHeight = 3
                detailitem = model2D.CreateDetailItem(symins)
                textvalues.Clear()
                i += 1
            model2D.Regenerate()
            self.tbmessage.append('球标已全部添加')

        except Exception:
            print('====================traverse_dim failed!=============================')
            print(traceback.format_exc())
            print('====================traverse_dim failed!=============================')

    # 尺寸位置排序
    def sort_dimlist(self, dimdict):
        dimgroup = []
        # 将分组字典转为列表，便于按视图原点位置将视图分组初步排序
        for item in dimdict.keys():
            dimgroup.append(dimdict[item])
        # 按视图位置排序
        for i in range(len(dimgroup) - 1):
            for j in range(len(dimgroup) - i - 1):
                o1x, o2x = dimgroup[j]['origin'][0], dimgroup[j + 1]['origin'][0]
                o1y, o2y = dimgroup[j]['origin'][1], dimgroup[j + 1]['origin'][1]
                if o1y < o2y:
                    dimgroup[j], dimgroup[j + 1] = dimgroup[j + 1], dimgroup[j]
                elif o1x > o2x:
                    dimgroup[j], dimgroup[j + 1] = dimgroup[j + 1], dimgroup[j]
        # 分视图内部排序 优先角度，角度相同按据中心距离由内到外
        for item in dimgroup:
            dimlist = item['dimlist']
            for i in range(len(dimlist) - 1):
                for j in range(len(dimlist) - i - 1):
                    if dimlist[j]['angle'] > dimlist[j + 1]['angle']:
                        dimlist[j], dimlist[j + 1] = dimlist[j + 1], dimlist[j]
                    elif dimlist[j]['angle'] == dimlist[j + 1]['angle'] and dimlist[j]['dist'] > dimlist[j + 1]['dist']:
                        dimlist[j], dimlist[j + 1] = dimlist[j + 1], dimlist[j]
        # 将排序后的尺寸分组列表统一输入到一个列表中
        dimlist = []
        for item in dimgroup:
            for t in item['dimlist']:
                dimlist.append(t)
        return dimlist

    # 清理球标
    def clear_indexsymbol(self):
        try:
            session = self.Asyncconnect.Session
            model = session.CurrentModel
            model2D = session.GetModel(model.FullName, EpfcMDL_DRAWING)
            detailitems = model2D.ListDetailItems(EpfcDETAIL_SYM_INSTANCE, None)
            if not detailitems is None:
                for item in detailitems:
                    symbolinstinstruction = item.GetInstructions(True)
                    symboldefinstruction = symbolinstinstruction.SymbolDef.GetInstructions()
                    symboldefname = symboldefinstruction.Name
                    if symboldefname == 'BOOLEAN':
                        item.Delete()
            model2D.Regenerate()
            self.tbmessage.append('球标已全部清理')
        except Exception:
            print('===================clear symbol failed!===========================')
            print(traceback.format_exc())
            print('===================clear symbol failed!===========================')

    def eval_distance(self, p1, p2):
        return pow(pow(p1[0] - p2[0], 2) + pow(p1[1] - p2[1], 2), 0.5)

    # 前置显示窗口
    def active_creo(self):
        hwndlist = []
        win32gui.EnumWindows(lambda hWnd, param: param.append(hWnd), hwndlist)
        for t in hwndlist:
            title = win32gui.GetWindowText(t)
            if re.match(r'.*?\(Active\) - Creo Parametric.*?|.*?\(活动的\) - Creo Parametric.*?', title):
                hwnd = win32gui.FindWindow(None, title)
                win32gui.ShowWindow(hwnd, win32con.SW_SHOWMAXIMIZED)
                win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0, 1920, 1080, win32con.SWP_SHOWWINDOW)
                win32gui.SetWindowPos(hwnd, win32con.HWND_NOTOPMOST, 0, 0, 1920, 1080, win32con.SWP_SHOWWINDOW)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = mainwin()
    win.show()
    sys.exit(app.exec_())
